home *** CD-ROM | disk | FTP | other *** search
/ Mac Power 1997 December / MACPOWER-1997-12.ISO.7z / MACPOWER-1997-12.ISO / AMUG / PROGRAMMING / WASTE Object Handlers 1.2.6.sit / WASTE Object Handlers 1.2.6 / Other Source / GetFileIcon.c next >
Text File  |  1997-07-21  |  17KB  |  620 lines

  1. // File Object Handler Utilities for the WASTE Text Engine
  2. // Part of the WASTE Object Handler Library by Michael Kamprath, kamprath@kagi.com
  3. // maintenance by John C. Daub, hsoi@eden.com
  4. //
  5. // v1.2 28 March 1996,  Cleaned up the file with precompiler directives, removing potential
  6. //                        warning messages, updated PB calls to new function names
  7. //
  8. // v1.2.1 4 April 1996. Fixed a bad bug where PBHGetVolParmsAsync() was getting called when
  9. //                        PBHGetVolParmsSync() should have been called instead.
  10. //
  11. // v1.2.3 24 September 1996  Changed calls to BlockMove() to use BlockMoveData() instead
  12. //
  13. // v1.2.4 17 January 1996.  The 14 routines prototyped in this file were previously all
  14. //                        declared as 'extern'.  If "Activate C++ Compiler" was turned on
  15. //                        this would generate inconsistent linkage errrors ('extern' object
  16. //                        redeclared as 'static').  Removed the 'extern' keyword from the
  17. //                        14 function prototypes and instead wrapped those same declarations
  18. //                        with a __cplusplus guard.  Also removed the 'static' keywords
  19.                         
  20. #ifndef __ICONS__
  21. #include <Icons.h>
  22. #endif
  23. #ifndef __FINDER__
  24. #include <Finder.h>
  25. #endif
  26. #ifndef __FOLDERS__
  27. #include <Folders.h>
  28. #endif
  29. #ifndef __ERRORS__
  30. #include <Errors.h>
  31. #endif
  32. #ifndef __RESOURCES__
  33. #include <Resources.h>
  34. #endif
  35. #ifndef __LOWMEM__
  36. #include <LowMem.h>
  37. #endif
  38. #include "GetFileIcon.h"
  39.  
  40. //#if PRAGMA_ALIGN_SUPPORTED
  41. //#pragma options align=mac68k
  42. //#endif
  43.  
  44. typedef struct getIconData { OSType        fileCreator;
  45.                              OSType        fileType;
  46.                              short        DTRefNum;
  47.                             } GetIconData;
  48. //#if PRAGMA_ALIGN_SUPPORTED
  49. //#pragma options align=reset
  50. //#endif
  51.  
  52. #ifdef __cplusplus
  53.     extern "C" {
  54. #endif
  55.  
  56. #ifndef true
  57. #define true 1
  58. #endif
  59.  
  60. #ifndef false
  61. #define false 0
  62. #endif
  63.  
  64.  
  65. Boolean IsVolEjected( short vRefNum );
  66. OSErr GetCustomFileIcon(FSSpec *filespec, IconSelectorValue iconSelector, Handle *theSuite);
  67. OSErr GetNormalFileIcon(CInfoPBRec *cpb, IconSelectorValue iconSelector, Handle *theSuite);
  68. void GetFinderFilename(StringPtr _finderFilename);
  69. pascal OSErr GetIconProc(ResType theType, Handle *theIcon, void *yourDataPtr);
  70. short FindDesktopDatabase(short firstVRefNum, OSType fileCreator); // returns a DT refnum or 0
  71. Boolean InOneDesktop(short vRefNum, OSType fileCreator, short *dtRefNum);
  72. pascal OSErr GetResourceIcons(Handle *theSuite, short theID, long theSelector);
  73. OSErr CopyEachIcon(Handle theSuite);
  74. pascal OSErr CopyOneIcon(ResType theType, Handle *theIcon, void *yourDataPtr);
  75. short FindGenericIconID(OSType theType, Boolean *inFinder);
  76. pascal OSErr Get1IconSuite(Handle *theSuite, short theID, long theSelector);
  77. pascal OSErr Get1Icon(ResType theType, Handle *theIcon, short *resID);
  78. pascal OSErr TestHandle(ResType theType, Handle *theIcon, void *yourDataPtr);
  79.  
  80. #ifdef __cplusplus
  81.     }
  82. #endif
  83.  
  84. /*    Custom icons numbered -16496 appear in aliases to volumes and
  85.     servers.  I don't know where this is documented.    */
  86. #define    kVolumeAliasIconResource    -16496
  87.  
  88.  
  89. /*    ------------------------------------------------------------------
  90.     GetFileIcon        Given a file specification for a file, folder, or
  91.                     volume, create an appropriate icon suite
  92.                     and find its label color.
  93.     ------------------------------------------------------------------ */
  94. pascal OSErr GetFileIcon(
  95. /* --> */    FSSpec                *thing,
  96. /* --> */    IconSelectorValue    iconSelector,
  97. /* <-- */    Handle                *theSuite)
  98. {
  99.     CInfoPBRec        cpb;
  100.     OSErr            err;
  101.  
  102.  
  103.     *theSuite = NULL;
  104.  
  105.     if( IsVolEjected(thing->vRefNum) )
  106.     {
  107.         err = volOffLinErr;
  108.     }
  109.     else
  110.     {
  111.         cpb.hFileInfo.ioVRefNum        = thing->vRefNum;
  112.         cpb.hFileInfo.ioDirID        = thing->parID;
  113.         cpb.hFileInfo.ioNamePtr        = thing->name;
  114.         cpb.hFileInfo.ioFDirIndex    = 0;
  115.         err = PBGetCatInfoSync( &cpb );
  116.  
  117.         if( !err )
  118.         {
  119.             if( (cpb.hFileInfo.ioFlAttrib & ioDirMask) == 0)    // file
  120.             {
  121.                 if(cpb.hFileInfo.ioFlFndrInfo.fdFlags & kHasCustomIcon)
  122.                 {
  123.                     err = GetCustomFileIcon(thing, iconSelector, theSuite );
  124.                 }
  125.                 else    // no custom icon
  126.                 {
  127.                     err = GetNormalFileIcon(&cpb, iconSelector, theSuite);
  128.                 }
  129.             }
  130.             // ----------- end of normal case --------------
  131.         }    
  132.     }
  133.  
  134.     // ------- error handler ---------
  135.     /*if(thing->parID == fsRtParID)    // a volume
  136.     {
  137.         if(err == volOffLinErr)
  138.         {
  139.             *labelColor = ttOffline;
  140.         }
  141.         err = GetVolumeIcon(thing->vRefNum, iconSelector, theSuite);
  142.     }*/
  143.  
  144.     return( err );
  145. }
  146.  
  147.  
  148. Boolean    IsVolEjected( short vRefNum )
  149. {
  150.     OSErr            err;
  151.     HVolumeParam    vol_pb;
  152.     
  153.     vol_pb.ioNamePtr    = NULL;
  154.     vol_pb.ioVRefNum    = vRefNum;
  155.     vol_pb.ioVolIndex    = 0;
  156.     err = PBHGetVInfoSync( (HParmBlkPtr )&vol_pb );
  157.     
  158.     return( (err == noErr) && (vol_pb.ioVDRefNum > 0) );
  159. }
  160.  
  161.  
  162.  
  163. OSErr    GetCustomFileIcon(
  164. /* --> */    FSSpec                *filespec,
  165. /* --> */    IconSelectorValue    iconSelector,
  166. /* <-- */    Handle                *theSuite)
  167. {
  168.     short    saveResFile, customResFile;
  169.     OSErr    err;
  170.     
  171.     saveResFile = CurResFile();
  172.     SetResLoad( false );
  173.     customResFile = FSpOpenResFile(filespec, fsRdPerm);
  174.  
  175.     SetResLoad( true );
  176.  
  177.     if(customResFile == -1)
  178.     {
  179.         err = ResError();
  180.     }
  181.     else
  182.     {
  183.         err = GetResourceIcons(theSuite, kCustomIconResource, iconSelector);
  184.         if( !err )
  185.         {
  186.             if( IsSuiteEmpty( *theSuite ) )
  187.             {
  188.                 err = GetResourceIcons(theSuite, kVolumeAliasIconResource, iconSelector);
  189.             }
  190.         }
  191.  
  192.         CloseResFile( customResFile );
  193.         UseResFile( saveResFile );
  194.     }
  195.     return( err );
  196. }
  197.  
  198.  
  199. OSErr    GetNormalFileIcon(
  200. /* --> */    CInfoPBRec            *cpb,
  201. /* --> */    IconSelectorValue    iconSelector,
  202. /* <-- */    Handle                *theSuite)
  203. {
  204.     OSErr            err;
  205. //    long            dataSize;
  206. //    Handle            iconData;
  207. //    Byte            iconType;
  208.     GetIconData        getData;
  209.     short            iconID;
  210.     Boolean            inFinder;
  211.     short            saveResFile, FinderResFile, sysVRefNum;
  212.     long            sysDirID;
  213.     Str255            finderName;
  214.     IconActionUPP    getIconProcPtr;
  215.  
  216.  
  217.     iconID = FindGenericIconID(cpb->hFileInfo.ioFlFndrInfo.fdType, &inFinder );
  218.     saveResFile = CurResFile();
  219.  
  220.     if( inFinder )
  221.     {
  222.         FindFolder(kOnSystemDisk, kSystemFolderType, kDontCreateFolder, &sysVRefNum, &sysDirID);
  223.  
  224.         SetResLoad( false );
  225.         GetFinderFilename( finderName );
  226.         FinderResFile = HOpenResFile(sysVRefNum, sysDirID, finderName, fsRdPerm);
  227.         SetResLoad( true );
  228.  
  229.         if(FinderResFile == -1)
  230.         {
  231.             err = ResError();
  232.         }
  233.         else
  234.         {
  235.             err = GetResourceIcons(theSuite, iconID, iconSelector);
  236.             CloseResFile( FinderResFile );
  237.         }
  238.     }
  239.     else    // icons in desktop DB or in System
  240.     {
  241.         getData.DTRefNum = FindDesktopDatabase(cpb->dirInfo.ioVRefNum,
  242.             cpb->hFileInfo.ioFlFndrInfo.fdCreator );
  243.  
  244.         if(getData.DTRefNum != 0)    // the right icons are in some desktop
  245.         {
  246.             err = NewIconSuite( theSuite );
  247.             if( !err )
  248.             {
  249.                 getData.fileCreator    = cpb->hFileInfo.ioFlFndrInfo.fdCreator;
  250.                 getData.fileType    = cpb->hFileInfo.ioFlFndrInfo.fdType;
  251.                 if(getData.fileType == kApplicationAliasType)
  252.                 {
  253.                     getData.fileType = 'APPL';
  254.                 }
  255.                 getIconProcPtr = NewIconActionProc( GetIconProc );
  256.                 err = ForEachIconDo(*theSuite, iconSelector, getIconProcPtr, &getData);
  257.                 DisposeRoutineDescriptor( getIconProcPtr );
  258.             }
  259.         }
  260.         if( (getData.DTRefNum == 0) || IsSuiteEmpty( *theSuite ) )
  261.         {
  262.             UseResFile( 0 );
  263.             err = GetResourceIcons(theSuite, iconID, iconSelector);
  264.         }
  265.     }
  266.  
  267.     UseResFile( saveResFile );
  268.  
  269.     return( err );
  270. }
  271.  
  272.  
  273. void GetFinderFilename(
  274. /* <-- */    StringPtr       _finderFilename)
  275. {
  276.     Str255          _defaultFinderFilename="¥pFinder";
  277.     StringPtr       _lowMemFinderName;
  278.  
  279.     _lowMemFinderName = LMGetFinderName();
  280.     if( (_lowMemFinderName != (StringPtr )nil) && (_lowMemFinderName[0] > 0))
  281.         BlockMoveData(_lowMemFinderName, _finderFilename, _lowMemFinderName[0]+1);
  282.     else
  283.         BlockMoveData(_defaultFinderFilename, _finderFilename, _defaultFinderFilename[0]+1);
  284. }
  285.  
  286.  
  287. /*    ------------------------------------------------------------------
  288.     GetIcon        This is an IconAction procedure to fill in one
  289.                     slot of an icon suite, given a file type, creator,
  290.                     and desktop database.
  291.     ------------------------------------------------------------------ */
  292. pascal OSErr GetIconProc(ResType theType, Handle *theIcon, void *yourDataPtr)
  293. {
  294.     OSErr            err;
  295.     GetIconData        *data;
  296.     DTPBRec            deskRec;
  297.  
  298.     err = noErr;
  299.     data = (GetIconData *)yourDataPtr;
  300.     *theIcon = NewHandle( kLarge8BitIconSize );
  301.  
  302.     if( !(*theIcon) )
  303.     {
  304.         err = memFullErr;
  305.     }
  306.     else
  307.     {
  308.         HLock( *theIcon );
  309.     
  310.         deskRec.ioDTRefNum        = data->DTRefNum;
  311.         deskRec.ioDTBuffer        = **theIcon;
  312.         deskRec.ioDTReqCount    = kLarge8BitIconSize;
  313.         deskRec.ioFileCreator    = data->fileCreator;
  314.         deskRec.ioFileType        = data->fileType;
  315.     
  316.         switch( theType )
  317.         {
  318.             case large1BitMask:
  319.                 deskRec.ioIconType = kLargeIcon;
  320.                 break;
  321.     
  322.             case large4BitData:
  323.                 deskRec.ioIconType = kLarge4BitIcon;
  324.                 break;
  325.     
  326.             case large8BitData:
  327.                 deskRec.ioIconType = kLarge8BitIcon;
  328.                 break;
  329.     
  330.             case small1BitMask:
  331.                 deskRec.ioIconType = kSmallIcon;
  332.                 break;
  333.     
  334.             case small4BitData:
  335.                 deskRec.ioIconType = kSmall4BitIcon;
  336.                 break;
  337.     
  338.             case small8BitData:
  339.                 deskRec.ioIconType = kSmall8BitIcon;
  340.                 break;
  341.             
  342.             default:
  343.                 // The desktop database does not have "mini" icons
  344.                 deskRec.ioIconType = 1000;
  345.                 break;
  346.         }
  347.  
  348.         err = PBDTGetIconSync( &deskRec );
  349.         if(err == noErr)
  350.         {
  351.             HUnlock( *theIcon );
  352.             SetHandleSize(*theIcon, deskRec.ioDTActCount);
  353.         }
  354.         else
  355.         {
  356.             DisposeHandle( *theIcon );
  357.             *theIcon = NULL;
  358.             err = noErr;
  359.         }
  360.     }
  361.     return( err );
  362. }
  363.  
  364.  
  365. /*    ------------------------------------------------------------------
  366.     Find_desktop_database            Find the reference number of a
  367.                                     desktop database containing icons
  368.                                     for a specified creator code.
  369.     The search begins on a specified volume, but covers all volumes.
  370.     ------------------------------------------------------------------ */
  371. short    FindDesktopDatabase(
  372. /* --> */    short    firstVRefNum,
  373. /* --> */    OSType    fileCreator)    // returns a DT refnum or 0
  374. {
  375. //    OSErr            err;
  376.     VolumeParam        vpb;
  377.     short            DTRefNum = 0;
  378.  
  379.     if( !InOneDesktop(firstVRefNum, fileCreator, &DTRefNum) )
  380.     {
  381.         vpb.ioNamePtr = NULL;
  382.         for(vpb.ioVolIndex = 1; PBGetVInfoSync((ParmBlkPtr )&vpb) == noErr; ++vpb.ioVolIndex)
  383.         {
  384.             if(vpb.ioVRefNum == firstVRefNum)
  385.                 continue;
  386.             if( InOneDesktop(vpb.ioVRefNum, fileCreator, &DTRefNum) )
  387.                 break;
  388.         }
  389.     }
  390.     return( DTRefNum );
  391. }
  392.  
  393.  
  394.  
  395. /*    ------------------------------------------------------------------
  396.     InOneDesktop            Determine whether the desktop database for
  397.                             one particular volume contains icons for
  398.                             a given creator code, and if so, return its
  399.                             reference number.
  400.     ------------------------------------------------------------------
  401. */
  402. Boolean    InOneDesktop(
  403. /* --> */    short    vRefNum,
  404. /* --> */    OSType    fileCreator,
  405. /* <-- */    short    *dtRefNum)
  406. {
  407.     OSErr        err;
  408.     DTPBRec        deskRec;
  409.     Boolean        retVal;
  410.     
  411.     HParamBlockRec         _myHPB;
  412.     GetVolParmsInfoBuffer  _infoBuffer;
  413.     
  414.     retVal = false;    // default to failure
  415.     deskRec.ioNamePtr = NULL;
  416.     deskRec.ioVRefNum = vRefNum;
  417.     
  418.     // check to make sure we've got a database first:
  419.     _myHPB.ioParam.ioNamePtr  = (StringPtr)nil;
  420.     _myHPB.ioParam.ioVRefNum  = vRefNum;
  421.     _myHPB.ioParam.ioBuffer   = (Ptr)&_infoBuffer;
  422.     _myHPB.ioParam.ioReqCount = sizeof(_infoBuffer);
  423.     if ( ((err=PBHGetVolParmsSync(&_myHPB))!=noErr) ||
  424.     ((_infoBuffer.vMAttrib&(1L<<bHasDesktopMgr))==0) )
  425.         return( retVal );
  426.  
  427.     err = PBDTGetPath( &deskRec );
  428.     if( !err )
  429.     {
  430.         /*    We want to ignore any non-icon data, such as the 'paul'
  431.             item that is used for drag-and-drop. */
  432.         deskRec.ioFileCreator = fileCreator;
  433.         deskRec.ioIndex = 1;
  434.         do
  435.         {
  436.             deskRec.ioTagInfo = 0;
  437.             err = PBDTGetIconInfoSync( &deskRec );
  438.             deskRec.ioIndex += 1;
  439.         }while( (err == noErr) && (deskRec.ioIconType <= 0) );
  440.     
  441.         if(err == noErr)
  442.         {
  443.             retVal = true;
  444.             *dtRefNum = deskRec.ioDTRefNum;
  445.         }
  446.     }
  447.     return( retVal );
  448. }
  449.  
  450.  
  451. pascal OSErr GetResourceIcons(
  452. /* <-- */    Handle    *theSuite,
  453. /* --> */    short    theID,
  454. /* --> */    long    theSelector)
  455. {
  456.     OSErr    err;
  457.     
  458.     err = Get1IconSuite(theSuite, theID, theSelector);
  459.     if(err == noErr)
  460.     {
  461.         err = CopyEachIcon( *theSuite );
  462.     }
  463.     return( err );
  464. }
  465.  
  466.  
  467. pascal OSErr CopyOneIcon(
  468. /* --> */    ResType        /*theType*/,
  469. /* <-> */    Handle        *theIcon,
  470. /* --- */    void        */*yourDataPtr*/)
  471. {
  472.     OSErr    err;
  473.     
  474.     if(*theIcon != NULL)
  475.     {
  476.         LoadResource( *theIcon );
  477.         err = HandToHand( theIcon );
  478.         if(err != noErr)
  479.             *theIcon = NULL;
  480.     }
  481.     return( noErr );
  482. }
  483.  
  484.  
  485. OSErr CopyEachIcon(
  486. /* <-> */    Handle theSuite)
  487. {
  488.     IconActionUPP    copyOneIconProc;
  489.     OSErr            err;
  490.     copyOneIconProc = NewIconActionProc( CopyOneIcon );
  491.     err = ForEachIconDo(theSuite, svAllAvailableData, copyOneIconProc, NULL);
  492.     DisposeRoutineDescriptor( copyOneIconProc );
  493.     return( err );
  494. }
  495.  
  496. //#if PRAGMA_ALIGN_SUPPORTED
  497. //#pragma options align=mac68k
  498. //#endif
  499. typedef struct genericIconInfo { OSType type; short id; } GenericIconInfo;
  500. //#if PRAGMA_ALIGN_SUPPORTED
  501. //#pragma options align=reset
  502. //#endif
  503.  
  504. static GenericIconInfo gGenericFinderIcons[]={ {'ifil',12500},
  505.                                                {'ifil',12500},
  506.                                                {'sfil',14000},
  507.                                                {'ffil',14500},
  508.                                                {'tfil',14501},
  509.                                                {'kfil',14750},
  510.                                                {'FFIL',15500},
  511.                                                {'DFIL',15750}
  512.                                               };
  513. static GenericIconInfo gGenericSysIcons[]={ {kContainerFolderAliasType,genericFolderIconResource},
  514.                                             {kContainerTrashAliasType,trashIconResource},
  515.                                             {kSystemFolderAliasType,systemFolderIconResource},
  516.                                             {'INIT',genericExtensionIconResource},
  517.                                             {'APPL',genericApplicationIconResource},
  518.                                             {'dfil',genericDeskAccessoryIconResource},
  519.                                             {'pref',genericPreferencesIconResource},
  520.                                             {kAppleMenuFolderAliasType,appleMenuFolderIconResource},
  521.                                             {kControlPanelFolderAliasType,controlPanelFolderIconResource},
  522.                                             {kExtensionFolderAliasType,extensionsFolderIconResource},
  523.                                             {kPreferencesFolderAliasType,preferencesFolderIconResource},
  524.                                             {kStartupFolderAliasType,startupFolderIconResource},
  525.                                             {kApplicationAliasType,genericApplicationIconResource},
  526.                                             {kExportedFolderAliasType,ownedFolderIconResource},
  527.                                             {kDropFolderAliasType,dropFolderIconResource},
  528.                                             {kSharedFolderAliasType,sharedFolderIconResource},
  529.                                             {kMountedFolderAliasType,mountedFolderIconResource}
  530.                                            };
  531.  
  532.  
  533. short    FindGenericIconID(
  534. /* --> */    OSType theType,
  535. /* <-- */    Boolean    *inFinder)
  536. {
  537.     
  538.    short id=genericDocumentIconResource; // default
  539.    GenericIconInfo *_icon, *_endIcon;
  540.    
  541.     for (_icon=gGenericFinderIcons,_endIcon=_icon+sizeof(gGenericFinderIcons)/sizeof(GenericIconInfo);
  542.          (_icon<_endIcon)&&(_icon->type!=theType); _icon++) ;
  543.     if (!(*inFinder=(_icon<_endIcon)))
  544.         for (_icon=gGenericSysIcons,_endIcon=_icon+sizeof(gGenericSysIcons)/sizeof(GenericIconInfo);
  545.              (_icon<_endIcon)&&(_icon->type!=theType); _icon++) ;
  546.     if (_icon<_endIcon)
  547.         id = _icon->id;
  548.  
  549.     return( id );
  550. }
  551.  
  552.  
  553. /*    --------------------------------------------------------------------
  554.     Get1IconSuite            Like GetIconSuite, but only looks in
  555.                             the current resource file.
  556.     
  557.     In case you're wondering why it would be necessary to ensure that
  558.     icons come from only one file, suppose you're looking at a
  559.     file that has its custom icon bit set, but for some reason does
  560.     not contain a custom icon, or at least not a full family.
  561.     Way down the resource chain, there may be another file, say a
  562.     font file, that does have a full family of custom icons. 
  563.     So you get an unexpected icon.
  564.     -------------------------------------------------------------------- */
  565.  
  566. pascal OSErr Get1IconSuite(
  567. /* <-- */    Handle    *theSuite,
  568. /* --> */    short    theID,
  569. /* --> */    long    theSelector)
  570. {
  571.     OSErr        err;
  572.     IconActionUPP    get1IconProc;
  573.  
  574.     err = NewIconSuite( theSuite );
  575.     if( !err )
  576.     {
  577.         get1IconProc = NewIconActionProc( Get1Icon );
  578.         err = ForEachIconDo(*theSuite, theSelector, get1IconProc, &theID);
  579.         DisposeRoutineDescriptor( get1IconProc );
  580.     }
  581.     return( err );
  582. }
  583.  
  584.  
  585. pascal OSErr Get1Icon(
  586. /* --> */    ResType    theType,
  587. /* <-> */    Handle    *theIcon,
  588. /* --> */    short    *resID)
  589. {
  590.     *theIcon = Get1Resource(theType, *resID);
  591.  
  592.     return( noErr );
  593. }
  594.  
  595.  
  596. pascal OSErr TestHandle(ResType /*theType*/, Handle *theIcon, void *yourDataPtr)
  597. {
  598.     if(*theIcon != NULL)
  599.         *(Boolean *)yourDataPtr = false;    // not empty!
  600.  
  601.     return( noErr );
  602. }
  603.  
  604.  
  605. Boolean IsSuiteEmpty( Handle theSuite )
  606. {
  607.     Boolean            retVal;
  608.     IconActionUPP    testHandleProc;
  609.  
  610.     testHandleProc = NewIconActionProc( TestHandle );
  611.     
  612.     retVal = true;
  613.     ForEachIconDo(theSuite, svAllAvailableData, testHandleProc, &retVal);
  614.     DisposeRoutineDescriptor( testHandleProc );
  615.  
  616.     return( retVal );
  617. }
  618.  
  619.  
  620.